
package flp.gui.view.annealing;

import flp.solvers.IOptimizationMonitor;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.Timer;

/**
 * Klasa nasluchujaca, odpowiedzialna za pobieranie aktualnych danych podczas
 * trwania optymalizacji a nastepnie zaznaczanie ich w odpowiednich strukturach.
 * 
 * @author Necro
 */
public class AnnealingOptimizationListener extends Thread implements IOptimizationMonitor {

    /** Kwant czasu o jaki odlegle sa od siebie momenty zaznaczania zebranych danych. */
    public static final int TIMESTEP = 100;
    
    /** Handler ktory stworzyl ta instancje monitora. */
    AnnealingSolverHandler parent;
    
    /** Timer obslugujacy zaznaczanie danych. */
    private Timer timer;
    
    /** Licznik prob. */
    private int tryCount;
    
    /** Licznik iteracji dla jednej proby. */
    private int iter;
    
    /** Wskaznik aktualnej temperatury. */
    private double temperature;
    
    /** Najlepszy koszt lokalnie.*/
    private int topCost;
    
    /** Najlepszy koszt globalnie.*/
    private int globalTopCost;
    
    /** Ilosc iteracji miedzy wyswietleniami. */
    private int n;
    
    /** Czas jaki uplynal od poczatku obliczen - do zaznaczenia na osi x. */
    private int timeElapsed;
    
    /** Flaga sygnalizujaca rozpoczecie optymalizacji. */
    private boolean started;
    
    /** Numer poprzedniej proby. */
    private int oldTryNr;
    
    /** Wykres dla najlepszej proby. */
    private AnnealingChart topChart;
    
    /** Najlepszy koszt dla aktualnie najlepszej proby. */
    private int topChartCost;
    
    /** Numer aktualnie najlepszej proby. */
    private int topTry;
    
    /** 
     * Konstruktor listenera.
     * 
     * @param parent Handler dla obslugiwanej optymalizacji.
     */
    public AnnealingOptimizationListener(AnnealingSolverHandler parent) {
        this.parent = parent;
        this.started = false;
        topChartCost=Integer.MAX_VALUE;
    }

    /**
     * Metoda pobierajaca wykres proby ktora dala najlepszy rezultat.
     * 
     * @return Wykres dla najlepszej proby.
     */
    public AnnealingChart getTopChart(){
        return topChart;
    }
    
    /**
     * Klasa odpowiedzialna za pobieranie danych
     * co okreslony kwant czasu.
     */
    class TimeredDataCollector implements ActionListener {
        
        /**
         * Zaznaczenie danych na wykresie oraz na panelu tekstowym.
         * 
         * @param e
         */
        public void actionPerformed(ActionEvent e) {
            if (n == 0) {
                return;
            }
            if (oldTryNr != tryCount) {
                oldTryNr=tryCount;
                timeElapsed=0;
                parent.chart=new AnnealingChart("Próba "+tryCount+" / "+parent.settings.getTries());
                parent.view.setChart(parent.chart.getChartPanel());
            }
            
            if (topChartCost > topCost){
                topChartCost=topCost;
                topChart=parent.chart;
                topTry=tryCount;
            }
            
            if (!parent.finished){
            //opcjonalnie dodać zerowanie wartości - redundantne
            parent.dataPanel.updateValues(tryCount, iter, topCost, globalTopCost, temperature);
            parent.chart.markData(topCost, timeElapsed);
            n=0;
            timeElapsed += TIMESTEP;
            } else {
                timer.stop();

                parent.view.setChart(topChart.getChartPanel());
                topChart.setTitle("Wykres dla najlepszej próby (#"+Integer.toString(topTry+1)+")");
                parent.dataPanel.fillBar();
                
            }
        }
    }

    @Override
    public void run() {
        timer = new Timer(TIMESTEP, new TimeredDataCollector());
        timer.setDelay(TIMESTEP);
        timer.start();
    }

    /** 
     * Metoda wywolywana z ciala Solver.computeSolution
     * zbierajaca dane z kazdej iteracji by je potem wyswietlic na wykresie.
     */
    public void markProgress(Object[] values) {
        iter = (Integer) values[0];
        tryCount = (Integer) values[1];
        topCost = (Integer) values[2];
        globalTopCost = (Integer) values[3];
        temperature = (Double) values[4];
        n++;
      
    }

    /** 
     * Metoda wywolywana z ciala Solver.computeSolution
     * zbierajaca dane z kazdej iteracji by je potem wyswietlic na wykresie.
     * @deprecated Tylko dla potrzeb testowania.
     */
    public void markProgress(String bestCost) {
  
    }
}
